#ifndef __MY_DATA__
#define __MY_DATA__

#include "Util.hpp"
#include <mutex>
#include <cstdlib>
#include <mysql/mysql.h>

#include "Log.hpp"

using namespace log_ns;

namespace aod
{
#define HOST "127.0.0.1"
#define USER "root"
#define PASS ""
#define NAME "aod_system"

    static MYSQL *MysqlInit()
    {
        //
        MYSQL *mysql = mysql_init(nullptr);
        if (mysql == nullptr)
        {
            LOG(ERROR, "init mysql instance failed!\n");
            return nullptr;
        }
        if (mysql_real_connect(mysql, HOST, USER, PASS, NAME, 0, nullptr, 0) == nullptr)
        {
            LOG(ERROR, "connect mysql server failed!\n");
            mysql_close(mysql);
            return nullptr;
        }
        mysql_set_character_set(mysql, "utf8");
        return mysql;
    }
    static void MysqlDestroy(MYSQL *mysql)
    {
        if (mysql != nullptr)
        {
            mysql_close(mysql);
        }
        return;
    }
    static bool MysqlQuery(MYSQL *mysql, const std::string &sql)
    {
        int ret = mysql_query(mysql, sql.c_str());
        if (ret != 0)
        {
            LOG(ERROR, "%s\n%s\n", sql, mysql_errno(mysql));
            return false;
        }
        return true;
    }
    class TableVideo
    {
    private:
        // ⼀个对象就是⼀个客⼾端，管理⼀张表
        MYSQL *_mysql;
        // 防备操作对象在多线程中使⽤存在的线程安全问题
        std::mutex _mutex;

    public:
        // 完成mysql句柄初始化
        TableVideo()
        {
            _mysql = MysqlInit();
            if (_mysql == nullptr)
            {
                exit(-1);
            }
        }
        // 释放msyql操作句柄
        ~TableVideo()
        {
            MysqlDestroy(_mysql);
        }

        // 新增-传⼊视频信息
        bool Insert(const Json::Value &video)
        {
#define INSERT_VIDEO "insert tb_video values(null, '%s', '%s', '%s', '%s');"
            std::string sql;
            // 防止简介过长
            sql.resize(4096 + video["info"].asString().size()); 
            if (video["name"].asString().size() == 0)
            {
                return false;
            }
            sprintf(&sql[0], INSERT_VIDEO, video["name"].asCString(),
                    video["info"].asCString(),
                    video["video"].asCString(),
                    video["image"].asCString());

            return MysqlQuery(_mysql, sql);
        }

        // 修改-传⼊视频id，和信息
        bool Update(int video_id, const Json::Value &video)
        {
#define UPDATE_VIDEO "update tb_video set name='%s', info='%s' where id=%d;"
            std::string sql;
            sql.resize(4096 + video["info"].asString().size()); // 防止简介过长
            sprintf(&sql[0], UPDATE_VIDEO, video["name"].asCString(),
                    video["info"].asCString(), video_id);
            return MysqlQuery(_mysql, sql);
        }

        // 删除-传⼊视频ID
        bool Delete(const int video_id)
        {
#define DELETE_VIDEO "delete from tb_video where id=%d;"
            std::string sql;
            sql.resize(1024);
            sprintf(&sql[0], DELETE_VIDEO, video_id);
            return MysqlQuery(_mysql, sql);
        }

        // 查询所有--输出所有视频信息
        bool SelectAll(Json::Value *videos)
        {
#define SELECTALL_VIDEO "select * from tb_video;"
            _mutex.lock();

            // 执行查询
            bool ret = MysqlQuery(_mysql, SELECTALL_VIDEO);
            if (ret == false)
            {
                _mutex.unlock();
                return false;
            }

            // 保存结果集
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == nullptr)
            {
                LOG(ERROR, "mysql store result failed!\n");
                _mutex.unlock();
                return false;
            }
            _mutex.unlock();
            // 获取结果行数
            int num_rows = mysql_num_rows(res);
            for (int i = 0; i < num_rows; i++)
            {
                // 获取结果行
                MYSQL_ROW row = mysql_fetch_row(res);
                Json::Value video;
                video["id"] = atoi(row[0]);
                video["name"] = row[1];
                video["info"] = row[2];
                video["video"] = row[3];
                video["image"] = row[4];
                videos->append(video);
            }
            // 释放结果集
            mysql_free_result(res);
            return true;
        }

        // 查询单个-输⼊视频id,输出信息
        bool SelectOne(int video_id, Json::Value *video)
        {
#define SELECTONE_VIDEO "select * from tb_video where id=%d"
            char sql[1024] = {0};
            sprintf(sql, SELECTONE_VIDEO, video_id);

            // 执行查询
            _mutex.lock();
            bool ret = MysqlQuery(_mysql, sql);
            if (ret == false)
            {
                _mutex.unlock();
                return false;
            }

            // 保存结果集
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == nullptr)
            {
                LOG(ERROR, "mysql store result failed!\n");
                _mutex.unlock();
                return false;
            }

            _mutex.unlock();

            int num_rows = mysql_num_rows(res);
            if (num_rows != 1)
            {
                LOG(ERROR, "have no data!\n");
                mysql_free_result(res);
                return false;
            }

            MYSQL_ROW row = mysql_fetch_row(res);
            (*video)["id"] = atoi(row[0]);
            (*video)["name"] = row[1];
            (*video)["info"] = row[2];
            (*video)["video"] = row[3];
            (*video)["image"] = row[4];

            mysql_free_result(res);
            return true;
        }
        // 模糊匹配-输⼊名称关键字，输出视频信息
        bool SelectLike(const std::string &key, Json::Value *videos)
        {
#define SELECTLIKE_VIDEO "select * from tb_video where name like '%%%s%%'"
            char sql[1024] = {0};
            sprintf(sql, SELECTLIKE_VIDEO, key.c_str());

            // 执行查询
            _mutex.lock();
            bool ret = MysqlQuery(_mysql, sql);
            if (ret == false)
            {
                _mutex.unlock();
                return false;
            }

            // 保存结果集
            MYSQL_RES *res = mysql_store_result(_mysql);
            if (res == nullptr)
            {
                LOG(ERROR, "mysql store result failed!\n");
                _mutex.unlock();
                return false;
            }

            _mutex.unlock();

            int num_rows = mysql_num_rows(res);
            for (int i = 0; i < num_rows; i++)
            {
                MYSQL_ROW row = mysql_fetch_row(res);
                Json::Value video;
                video["id"] = atoi(row[0]);
                video["name"] = row[1];
                video["info"] = row[2];
                video["video"] = row[3];
                video["image"] = row[4];
                videos->append(video);
            }
            //释放结果集
            mysql_free_result(res);
            return true;
        }
    };
}
#endif